#pragma once
#include "MovingObject.h"
#include "../SGD Wrappers/SGD_InputManager.h"
#include "../SGD Wrappers/SGD_AudioManager.h"

class Game;
class GameplayState;
class TileSystem;
class Augment;
class Player : public MovingObject
{
public:
	Player();
	virtual ~Player();

	/**********************************************************/
	// State
	//	- functions and variables pertaining to player states
	enum State{ IDLE, WALKING, JUMPING, CLIMBING, STAIRS, MOVEMENT, DEAD};
	State state = State::WALKING;
	SGD::Point lastPos;

	/**********************************************************/
	// Interface:
	//	- virtual functions for children classes to override
	virtual void	Update(float elapsedTime)		override;
	virtual void	Render(void)					override;
	void			Input(void);
//	virtual SGD::Rectangle GetRect(void)	const			override;
	virtual int		GetType(void)	const			override	{ return OBJ_PLAYER; }
	virtual void	HandleCollision(GameObject* pOther)	override;
	
	//functionality methods
	void UseLeft();
	void UseRight();
	void UseInteract();
	void UseJump();
	void UseMovement();
	void UseDown();
	void Shoot();

	//enter different state methods
	void EnterIdle();
	void EnterWalking();
	void EnterJumping();
	void EnterClimbing();
	void EnterStairs();
	void EnterDead();
	void StartDashing();
	void StartBackDashing();
	void StartSliding();
	void HotSwapFunctionality();
	void AugmentTableFunctionality();
	void AugmentTableInterface();
	void ModifyScore(int amount);

	void HandleEvent(const SGD::Event* pEvent);

	void TakeAugment(GameObject* pOther, int slot);

	/**********************************************************/
	// Accessors:
	std::string& GetName(void) { return name; }
	Augment* GetMoveSlot(void) const { return m_aMoveSlot; }
	Augment* GetBulletSlot(void) const { return m_aBulletSlot; }
	Augment* GetStyleSlot(void) const { return m_aStyleSlot; }
	bool GetIsAlive() const { return isAlive; }
	int GetNextLevel() const { return nextLevel; }
	int GetScore(void) const { return score; }
	bool GetUCCPortal(void)	{ return uccPortal; }
	int GetShieldCount() const { return m_iShieldCount; }
	Augment * GetHotSwap(int index) { return HotSwap[index]; }
	int GetDamage() const { return m_iDamage; }
	float GetDashCoolDown() const { return dashCooldown; }
	float GetSlideCoolDown() const { return slideCoolDown; }
	float GetBackDashCoolDown() const { return backDashCoolDown; }
	float GetMaxDashCD() const { return maxDashCD; }
	float GetMaxBackDashCD() const { return maxBackDashCD; }
	float GetMaxSlideCD() const { return maxSlideCD; }
	int GetComboMult() const { return m_iComboMultipiler; }
	int GetMaxCombo() const { return m_iMaxComboGained; }
	bool GetIsJumping() const { return m_bIsJumping; }
	bool GetCollidedWithEnemy() const { return collidedWithEnemy; }
	float GetMinPosInWorld() const { return minPosInWorld; }

	// Mutators:
	void SetCollidedWithEnemy(bool collided) { collidedWithEnemy = collided; }
	void SetMoveSlot(Augment* move) { m_aMoveSlot = move; }
	void SetBulletSlot(Augment* bullet) { m_aBulletSlot = bullet; }
	void SetStyleSlot(Augment* style) { m_aStyleSlot = style; }
	void SetIsAlive(bool alive) { isAlive = alive; }
	void SetNextLevel(int next) { nextLevel = next; }
	void SetScore(const int s) { score = s; }
	void SetStunTimer(float set) { m_fStunTimer = set; }
	void SetName(string set) { name = set; }
	void SetHotSwap(int index, Augment *set) { HotSwap[index] = set; }
	void SetMinPosInWorld(float xPos)	{ minPosInWorld = xPos; }
	void SetShieldCount(int count) { m_iShieldCount = count; }
	void AddMoveTable(Augment *add) { AugmentMoveTable.push_back(add); }
	void AddWeaponTable(Augment *add) { AugmentWeaponTable.push_back(add); }
	Augment *GetWeaponTable(unsigned int index) { return index < AugmentMoveTable.size() ? AugmentMoveTable[index] : nullptr; }
	Augment *GetMoveTable(unsigned int index) { return index < AugmentWeaponTable.size() ? AugmentMoveTable[index] : nullptr; }
	void SetDamage(int d) { m_iDamage = d; }
	void SetAppropiateFireRate();
	//to update all timers when necessary
	void UpdateTimers(float elapsedTime);
	void SetClosestEnemy(GameObject* enemy) { closestenemy = enemy; }
	GameObject* GetClosestEnemy() const { return closestenemy; }
private:
	SGD::InputManager* pInput;
	SGD::AudioManager* pAudio = SGD::AudioManager::GetInstance();
	Game* theGame;
	GameplayState *gameplay;
	TileSystem *TS;

	std::string name = "MAGIKUS";

	bool isAlive = true;

	Augment * m_aMoveSlot = nullptr;
	Augment * m_aBulletSlot = nullptr;
	Augment * m_aStyleSlot = nullptr;
	Augment * HotSwap[4];
	std::vector<Augment*> AugmentMoveTable;
	std::vector<Augment*> AugmentWeaponTable;
	bool m_bTouchingMoveAugment = false;
	bool m_bTouchingWeaponAugment = false;
	bool m_bTouchingMoveTable = false;
	bool m_bTouchingWepTable = false;
	bool m_bUsingBulletTable = false;
	bool m_bUsingShotTable = false;
	bool m_bUsingMoveTable = false;
	bool collidedWithEnemy = false;

	int m_nCursor = 0;

	GameObject* closestenemy;
	//player's score
	int score = 0;
	int m_iComboMultipiler = 1;
	int m_iCurrComboCount = 1;
	int m_iMaxComboGained = 1;
	float m_fComboTimer = 0;
	int m_iDamage = 100;

	//all shield information
	int m_iShieldCount = 0;
	float Shieldtimer = 0.0f;
	bool shielded = false;

	SGD::HAudio	m_AAugSwap = SGD::INVALID_HANDLE;

	//portal information
	bool levelPortal = false;
	bool uccPortal = false;
	bool portalCollision = false;
	bool warpPortal = false;
	SGD::Point warpLoc;

	//Climbing information
	bool onLadder = false;
	bool onStairs = false;
	
	//the player's current level
	int level = 0;
	int nextLevel = 1;
	float minPosInWorld = 0;
	
	//some ability information
	bool usingAbility = false;
	bool dashing = false;
	bool backDashing = false;
	bool sliding = false;
	bool m_bIsJumping = false;

	float dashTimer = 0.0f;
	float backDashTimer = 0.0f;
	float slideTimer = 0.0f;
	float dashDuration = 0.2f;

	float dashCooldown = 0.0f;
	float backDashCoolDown = 0.0f;
	float slideCoolDown = 0.0f;
	float maxDashCD = 3.0f;
	float maxBackDashCD = 3.0f;
	float maxSlideCD = 3.0f;
	float collidedTimer = 0.0f;

	//player's sound effects
	SGD::HAudio gettingHitSFX;
	SGD::HAudio deathSound;
	bool test = false;

	SGD::HAudio slideSFX;
	SGD::HAudio jumpingSFX;
	SGD::HAudio dashingSFX;

	SGD::HTexture armImage;

	SGD::HAudio getPickUp;
};